////////////////////////////////////////////////////////////////////////////////////////////////////

#include "CGlobals.h"
#include "CLevelEditor.h"
#include "CUserInterface.h"
#include "CPlaneCamera.h"
#include "CGridSceneNode.h"
#include "CMayaCameraAnimator.h"
#include "CtrolPointCamera.h"
#include "ChangeCameraAnimator.h"
#include "CinematicCamera.h"
#include "FpsIrrFactory.h"
#include "Irrlicht.h"
//#include "IGUISpriteBank.h"
#include "CGUIFont.h"
#include "CGUITreeCtrl.h"
#include "CEventReceiver.h"
#include "FpsSceneManager.h"
//#include "SIrrCreationParameters.h"

#include <windows.h>

extern CLevelEditor* editor;
extern CUserInterface* ui;

////////////////////////////////////////////////////////////////////////////////////////////////////

#define VERSION_MAJOR 0
#define VERSION_MINOR 1
#define VERSION_BUILD 0

//  0.1.0 rewritten cinematic system

// 0.0.7 added animation time for animations

// 0.0.6 added animation support for cinematic editor

// 0.0.5 added game objects for everything 	

// 0.0.4 changed saving system - now we have separate files for rooms and groups

// 0.0.3 added health for enemy
////////////////////////////////////////////////////////////////////////////////////////////////////

u32 CGlobals::m_versionMajor = VERSION_MAJOR;
u32 CGlobals::m_versionMinor = VERSION_MINOR;
u32 CGlobals::m_versionBuild = VERSION_BUILD;

////////////////////////////////////////////////////////////////////////////////////////////////////

CGlobals::CGlobals()
{	
	m_activeCameraIndex = 0;
	m_gridNode = 0;	
	m_gridSize = 10000;
	m_hideGUI = false;
}

////////////////////////////////////////////////////////////////////////////////////////////////////

CGlobals::~CGlobals()
{
	device->drop();
}

////////////////////////////////////////////////////////////////////////////////////////////////////

int CGlobals::init()
{
	m_versionStr = L"Version: ";
	m_versionStr +=VERSION_MAJOR;
	m_versionStr +=L".";
	m_versionStr +=VERSION_MINOR;
	m_versionStr +=L".";
	m_versionStr +=VERSION_BUILD;

	eventReceiver = new CEventReceiver();

	
	SIrrlichtCreationParameters p;
		p.DriverType =  video::EDT_OGLES1;
		p.WindowSize = dimension2d<s32>(1024, 768);
		p.Bits = 32;
		p.Fullscreen = false;
		p.Stencilbuffer = false;
		p.Vsync = false;
		p.EventReceiver = eventReceiver;
		p.AntiAlias = false ;
		

		//new FpsIrrFactory();
		device = createDeviceEx(p);

	//device->setResizeAble(true);	

	if (device == 0)
		return 1; 

	device->setWindowCaption(L"Level Editor - Untitled.irr");
	driver = device->getVideoDriver();

	sceneManager = device->getSceneManager();
	sceneManager->clear();

	guienv = device->getGUIEnvironment();
	IGUISkin* newskin = guienv->createSkin( gui::EGST_WINDOWS_CLASSIC);
	guienv->setSkin(newskin);

	guienv->getSkin()->setColor(EGDC_3D_FACE, SColor(255, 175, 175, 175));
	guienv->getSkin()->setColor(EGDC_3D_HIGH_LIGHT, SColor(255, 210, 210, 210));

	//guienv->getSkin()->setColor(EGDC_3D_FACE, SColor(230, 191, 206, 210));
	//guienv->getSkin()->setColor(EGDC_3D_SHADOW, SColor(230, 85, 113, 121));
	//guienv->getSkin()->setColor(EGDC_WINDOW, SColor(230, 205, 231, 245));
	//guienv->getSkin()->setColor(EGDC_3D_HIGH_LIGHT, SColor(230, 180, 210, 222));	
	
	newskin->drop();

	loadFonts();	

//cvp temp	guienv->setToolTipLaunchTime(50000000);	
//cvp temp	guienv->setToolTIpRefreshTime(50000000);

	m_mayaCameraFar	= 10000.0f;
	m_mayaCameraRotate = -150.0f;
	m_mayaCameraZoom = 10000.0f;
	m_mayaCameraTranslate = 3000.0f;

	initScene();

	return 0;
}
////////////////////////////////////////////////////////////////////////////////////////////////////
void CGlobals::close()
{
	delete(eventReceiver);	

}
////////////////////////////////////////////////////////////////////////////////////////////////////
void CGlobals::setActiveCamera (int cameraIndex)
{	
	camera[cameraIndex]->setInputReceiverEnabled(true);
	sceneManager->setActiveCamera(camera[cameraIndex]);
	m_activeCameraIndex = cameraIndex;
}
////////////////////////////////////////////////////////////////////////////////////////////////////
void CGlobals::createCameras() 
{   		
	
	camera[MAYA_CAMERA] = sceneManager->addCameraSceneNode();
	camera[MAYA_CAMERA]->addAnimator(new CSceneNodeAnimatorCameraMaya(device->getCursorControl(),
		m_mayaCameraRotate, m_mayaCameraZoom , m_mayaCameraTranslate ));

	camera[MAYA_CAMERA]->setNearValue(0.1f);
	camera[MAYA_CAMERA]->setFarValue( m_mayaCameraFar);


	camera[FPS_CAMERA] = sceneManager->addCameraSceneNodeFPS(0, 100.0f, 500.0f);

	camera[FPS_CAMERA]->setNearValue(0.1f);
	camera[FPS_CAMERA]->setFarValue(10000.0f);


	vector3df vx(1,0,0), vy(0,1,0), vz(0,0,1);
	camera[CAMERA_XZ] = sceneManager->addCameraSceneNode(0);
	camera[CAMERA_XZ]->addAnimator(new CPlaneCameraAnimator(camera[CAMERA_XZ], vx, vz));
	camera[CAMERA_XY] = sceneManager->addCameraSceneNode(0);
	camera[CAMERA_XY]->addAnimator(new CPlaneCameraAnimator(camera[CAMERA_XY], -vy, vx));
	camera[CAMERA_YZ] = sceneManager->addCameraSceneNode(0);
	camera[CAMERA_YZ]->addAnimator(new CPlaneCameraAnimator(camera[CAMERA_YZ], vy, vz));

	camera[CAMERA_XZ]->setNearValue(1.f);
	camera[CAMERA_XZ]->setFarValue(10000.0f);

	camera[CAMERA_XY]->setNearValue(1.f);
	camera[CAMERA_XY]->setFarValue(10000.0f);

	camera[CAMERA_YZ]->setNearValue(1.f);
	camera[CAMERA_YZ]->setFarValue(10000.0f);

	const float FOV			=	45.354790f;

	camera[CONTROL_POINT_CAMERA] = sceneManager->addCameraSceneNode(0);
	camera[CONTROL_POINT_CAMERA]->addAnimator(new CCtrolPointCameraAnimator(camera[CONTROL_POINT_CAMERA]));
	camera[CONTROL_POINT_CAMERA]->setUpVector(vector3df(0.0f,0.0f,1.0f));
	camera[CONTROL_POINT_CAMERA]->setNearValue(1.f);
	camera[CONTROL_POINT_CAMERA]->setFarValue(1000000.f);
	camera[CONTROL_POINT_CAMERA]->setFOV(FOV * irr::core::DEGTORAD * 320.0f/480.0f);


	camera[CHANGE_CAMERA] = sceneManager->addCameraSceneNode(0);
	camera[CHANGE_CAMERA]->addAnimator(new CChangeCameraAnimator(camera[CHANGE_CAMERA]));
	camera[CHANGE_CAMERA]->setUpVector(vector3df(0.0f,0.0f,1.0f));
	camera[CHANGE_CAMERA]->setNearValue(1.f);
	camera[CHANGE_CAMERA]->setFarValue(1000000.f);
	camera[CHANGE_CAMERA]->setFOV(FOV * irr::core::DEGTORAD * 320.0f/480.0f);

	camera[CINEMATIC_CAMERA] = sceneManager->addCameraSceneNode(0);
	camera[CINEMATIC_CAMERA]->addAnimator(new CCinematicCameraAnimator(camera[CINEMATIC_CAMERA]));
	camera[CINEMATIC_CAMERA]->setUpVector(vector3df(0.0f,0.0f,1.0f));
	camera[CINEMATIC_CAMERA]->setNearValue(1.f);
	camera[CINEMATIC_CAMERA]->setFarValue(1000000.f);
	camera[CINEMATIC_CAMERA]->setFOV(FOV * irr::core::DEGTORAD * 320.0f/480.0f);
	

	setActiveCamera(CAMERA_XY);

	camera[MAYA_CAMERA]->setPosition(vector3df(0.0f, 100.0f, 100.0f));	
	camera[MAYA_CAMERA]->setTarget(vector3df(0.0f, 0.0f, 0.0f));
	camera[MAYA_CAMERA]->setUpVector(vector3df(0.0f, 0.0f, 1.0f));

	camera[FPS_CAMERA]->setUpVector(vector3df(0.0f, 0.0f, 190.0f));	
}
////////////////////////////////////////////////////////////////////////////////////////////////////
void CGlobals::initScene()
{
	createCameras();

	m_gridNode = new CGridSceneNode( -1, 100, m_gridSize, SColor(128, 200, 200, 200), 5, 
		SColor(255, 190, 255, 190), true);
	sceneManager->getRootSceneNode()->addChild(m_gridNode);

	sceneManager->getVideoDriver()->setFog(SColor(0, 200, 200, 200),EFT_FOG_LINEAR, 1500.f, 50000.f, 0.00001f, false, false);
	IGUISkin* skin = guienv->getSkin();
	IGUIFont* font = skin->getFont();

}
////////////////////////////////////////////////////////////////////////////////////////////////////
void CGlobals::loadFonts()
{
	IGUISkin* skin = guienv->getSkin();
	CGUIFont* font = static_cast<CGUIFont*>(guienv->getFont("font_simple1.bmp"));
	if (font)
	{
		IGUISpriteBank* pSpriteBank = font->getSpriteBank();
		for (int i=0; i < pSpriteBank->getTextureCount(); i++)
		{
			//pSpriteBank->getTexture(i)->setMinFilter(irr::video::ETFT_NEAREST);
			//pSpriteBank->getTexture(i)->setMagFilter(irr::video::ETFT_NEAREST);
		}

		skin->setFont(font);
	}
}
////////////////////////////////////////////////////////////////////////////////////////////////////
void CGlobals::run( u32 delta)
{
	m_fpsStr = L"";
	m_fpsStr+= driver->getFPS();
	

	if (device->isWindowActive())
	{
		//driver->setClearColor(irr::video::SColor(255, 126, 160, 146));
		driver->beginScene(true, true, irr::video::SColor(255, 126, 160, 146));
		//driver->clearBuffers(irr::video::EFB_COLOR | irr::video::EFB_DEPTH); 

		if (!editor->m_SaveLoadProgressDraw)
		{
			// Update aspect ratio in case the user resized the window
			sceneManager->getActiveCamera()->setAspectRatio(
				(f32)driver->getCurrentRenderTargetSize().Width /
				(f32)driver->getCurrentRenderTargetSize().Height);			
						
			//sceneManager->update( delta , true );

			//int time = ( (CFpsSceneManager*)g->sceneManager )->getSceneTime();

			//
			//sceneManager->getActiveCamera()->OnAnimate( time );

			//if (ui->IsEffectsTabSelected())
			//{
			//	editor->UpdateEffects( time );
			//}
			
			sceneManager->drawAll();
			editor->drawSelectedObjects();
			editor->drawWaypointConnections();
			editor->drawCameraAreas();
		//	editor->drawGridWaypointConnections();
			editor->drawFocusBoundingBox();
			editor->drawCameraTarget();

			if(!m_hideGUI)
			{
				//driver->beginScene();
				editor->drawObjectManipulationControls();
				editor->drawObjectSelectionHandles();
				//driver->endScene();
			}

			if(editor->IsPlayingCinematic())
			{
				//driver->beginScene();				
				editor->drawPlayCinematicInfo();
				//driver->endScene();
			}

			ui->updateWindowsPosition();
		}
		
		if(!m_hideGUI)
		{			
			guienv->drawAll();

			const dimension2d<u32> screen = g->driver->getScreenSize();				

			if (editor->m_SaveLoadProgressDraw)
			{			
				stringw pStr = stringw("Objects processed: ") + stringw(editor->m_SaveLoadProgress);						
				guienv->getSkin()->getFont()->draw(pStr.c_str(), rect<s32>(0, 0, screen.Width, 18), SColor(255, 0, 255, 0), true, true);
			}		
			else
			{
				if (editor->m_bPositionObjOnInsert)
				{
					guienv->getSkin()->getFont()->draw(L"Left click to insert objects, right click to end objects insertion",
					rect<s32>(0, 0, screen.Width, 18),
					SColor(255, 255, 0, 0), true, true);
				}
				else
				{
	//				io::IAttributes * attr = sceneManager->getParameters();

	//				s32 calls = attr->getAttributeAsInt ( "calls" );
	//				s32 culled = attr->getAttributeAsInt ( "culled" );
	//				s32 bindings = driver->getTextureBindingCount();//attr->getAttributeAsInt ( "bindings" );
	//				s32 drawcalls = driver->getDrawCallCount();//attr->getAttributeAsInt ( "drawcalls" );
	//				s32 drawcalls2d = driver->getDrawCall2DCount();

	//#if defined(_DEBUG)
	//				m_fpsStr+= " DEBUG ";						
	//#else
	//				m_fpsStr+= " RELEASE ";				
	//#endif 

	//				m_fpsStr+= " Calls ";
	//				m_fpsStr+= calls;
	//				
	//				m_fpsStr+= " culled ";
	//				m_fpsStr+= culled;

	//				m_fpsStr+= " / ";
	//				m_fpsStr+= calls;

	//				m_fpsStr+= "  Bindings: ";
	//				m_fpsStr+= bindings;

	//				m_fpsStr+= "  Drawcalls: ";
	//				m_fpsStr+= drawcalls;
	//				m_fpsStr+= " / ";
	//				m_fpsStr+= drawcalls2d;


	//				guienv->getSkin()->getFont()->draw(m_fpsStr.c_str(),
	//				rect<s32>(0, 0, screen.Width, 18),
	//				SColor(255, 0, 255, 0), true, true);
				}
			}
			
		}

		driver->endScene();
//		driver->swapBuffers(0); 

		editor->doUpdateControls();
		//device->yield();
	}
	else
	{
		((CGUITreeCtrl*)ui->m_sceneGraphTree)->m_picked = false;
		//device->yield();
	}
}
////////////////////////////////////////////////////////////////////////////////////////////////////
void CGlobals::switchGrid()
{
	if (!m_gridNode)
		return;
	m_gridNode->setVisible(!m_gridNode->isVisible());
}
////////////////////////////////////////////////////////////////////////////////////////////////////
stringc CGlobals::extractFileName(stringc* fileName)
{
	stringc result;
	
	s32 lastSlash = fileName->findLast('/');
	const s32 lastBackSlash = fileName->findLast('\\');
	s32 last = lastSlash > lastBackSlash ? lastSlash : lastBackSlash;

	if (last < 0)
		result = fileName->c_str();
	else
		result = fileName->subString(last + 1, fileName->size() - last);
	
	return result;
}
////////////////////////////////////////////////////////////////////////////////////////////////////
stringc CGlobals::getRelativePath(stringc fromPath, stringc toFile)
{
	fromPath.make_lower();
	toFile.make_lower();

	int len1 = fromPath.size();
	int len2 = toFile.size();

	int minLen = len1;
	if (minLen > len2) minLen = len2;

	int i = 0;
	for (i = 0; i < minLen; i++)
	{
		if (fromPath[i] != toFile[i]) break;
	}

	if ( i == 0 ) return toFile;

	if ( i == minLen ) return stringc(".") + toFile.subString(i, toFile.size() - i);

	stringc fromPathSubStr = fromPath.subString(i, fromPath.size() - i);
	int pos = fromPathSubStr.findFirstChar("\\", 1);

	stringc str("..\\");
	while (pos != -1)
	{
		str += "..\\";
		pos = fromPathSubStr.findNext('\\', pos + 1);
	}

	return str + toFile.subString(i, toFile.size() - i);

	//int n = strcmp(fromPath.c_str(), toPath.c_str());
	//int pos = fromPath.find(toPath.c_str());
	//if (pos < 0)
	//	return fromPath;
	//else
	//	return stringc(fromPath.subString(toPath.size() + 1, fromPath.size() - toPath.size()));
}
////////////////////////////////////////////////////////////////////////////////////////////////////
void debug_out(const char* fmt, ...)
{
	char str[1024];
	va_list arg_list;

	va_start(arg_list, fmt);
	vsprintf(str, fmt, arg_list);

	printf("%s\n", str);
	OutputDebugStringA(str);

}

/////////////////////////////////////////////////////////////////////////////////////////////////////
void ResizeWindow(HWND hwnd, int width, int height)
{
	if( hwnd )
	{			
		LONG_PTR style  = WS_THICKFRAME | WS_SYSMENU | WS_CAPTION | WS_CLIPCHILDREN 
			| WS_CLIPSIBLINGS | WS_MINIMIZEBOX | WS_MAXIMIZEBOX;

		RECT clientSize;
		clientSize.top = 0;
		clientSize.left = 0;
		clientSize.right = width;
		clientSize.bottom = height;

		AdjustWindowRect(&clientSize, style, FALSE);

		const s32 realWidth = clientSize.right - clientSize.left;
		const s32 realHeight = clientSize.bottom - clientSize.top;

		const s32 windowLeft = (GetSystemMetrics(SM_CXSCREEN) - realWidth) / 2;
		const s32 windowTop = (GetSystemMetrics(SM_CYSCREEN) - realHeight) / 2;

		SetWindowPos(hwnd, HWND_TOP, windowLeft, windowTop, realWidth, realHeight,
			SWP_FRAMECHANGED | SWP_NOMOVE | SWP_SHOWWINDOW);		
	}
}

void CGlobals::OnOffDeviceEmulatorMode(bool on)
{
	if(on)
	{
		m_screenSizeSaved = driver->getScreenSize();

		device->setWindowCaption(L"LevelEditor-Device Emulator");
	
		HWND hwnd = FindWindow(NULL,L"LevelEditor-Device Emulator");
		ResizeWindow(hwnd, k_deviceWidth, k_deviceHeight);		

		ui->HideRestoreWindows(true);
		m_hideGUI = true;
	}
	else
	{
		HWND hwnd = FindWindow(NULL,L"LevelEditor-Device Emulator");
		ResizeWindow(hwnd, m_screenSizeSaved.Width, m_screenSizeSaved.Height);			

		ui->HideRestoreWindows(false);
		editor->updateEditorCaption();
		m_hideGUI = false;
	}
}

void CGlobals::AddToFrameNameMap(const char* frameName, int frameID)
{
	m_frameNameMap[frameName] = frameID;
}

int CGlobals::FindFrameIDByName(const char* frameName)
{
	FrameNameMap::iterator e = m_frameNameMap.find(frameName);
	if(e!=m_frameNameMap.end())
	{
		return (*e).second;
	}
	else
	{
		return -1;
	}
}